﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace CodeRepositoryConsole.FCL.IO
{
    class FileToByteArray
    {
        /// <summary>
        /// Read by File.ReadAllBytes
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        /// <see cref="https://stackoverflow.com/questions/2030847/best-way-to-read-a-large-file-into-a-byte-array-in-c"/>
        public byte[] FileToByteArrayByReadAllBytes(string filePath)
        {
            // this method is limited to 2^32 byte file(4.2 GB)
            // File.ReadAllBytes throws OutOfMemoryException with big files (tested with 630 MB file and it failed)
            return File.ReadAllBytes(filePath);
        }


        // another method see http://www.yoda.arachsys.com/csharp/readbinary.html

        /// <summary>
        /// Read data into a complete array, throwing an EndOfStreamException
        /// if the stream run out of data first, or if an IOException
        /// naturally occurs.
        /// </summary>
        /// <param name="stream">The stream to read data from</param>
        /// <param name="data">The array to read data into. The array
        /// will be completely filled from the stream,so an appropriate
        /// size must be given.</param>
        public static void ReadWholeArray(Stream stream, byte[] data)
        {
            int offset = 0;
            int remaining = data.Length;
            while (remaining > 0)
            {
                int read = stream.Read(data, offset, remaining);
                if (read <= 0)
                {
                    throw new EndOfStreamException
                        (String.Format("End of stram reached with {0} bytes left to read", remaining));
                }
                remaining -= read;
                offset += read;
            }
        }

        /**
         * a.
         * Sometimes, you don't know the length of the stream in advance(for instance a network stream) 
         * and just want to read the whole lot into a buffer. Here's a method to do just that:
         * b.
         * Stream.Read doesn't guarantee that it will read everything it's asked for
         */

        /// <summary>
        /// Read data from a stream until the end is reached. The
        /// data is returned as a byte array. An IOException is
        /// thrown if any of the underlying IO call fail.
        /// </summary>
        /// <param name="stream">The stream to read data from</param>
        /// <returns></returns>
        public static byte[] ReadFully(Stream stream)
        {
            byte[] buffer = new byte[32768]; // 32 * 1024
            using (MemoryStream ms = new MemoryStream())
            {
                while (true)
                {
                    // Stream.Read doesn't guarantee that it will read everything it's asked for.
                    // If you're reading from a network stream, for example, it may read one packet's
                    // worth and then return, even if there will be more data soon.
                    int read = stream.Read(buffer, 0, buffer.Length);
                    if (read <= 0)
                    {
                        return ms.ToArray();
                    }
                    ms.Write(buffer, 0, read);
                }
            }
        }

        /// <summary>
        /// Read data from a stream until the end is reached. The
        /// data is returned as a byte array. An IOException is
        /// thrown if any of the underlying IO call fail.
        /// </summary>
        /// <param name="stream">The stream to read data from</param>
        /// <param name="initialLength">The initial buffer length</param>
        /// <returns></returns>
        public static byte[] ReadFully(Stream stream, int initialLength)
        {
            // If we've been pass an unhelpful initial length, just
            // use 32K.
            if (initialLength < 1)
            {
                initialLength = 32768;
            }

            byte[] buffer = new byte[initialLength];
            int read = 0; // Stream.Read don't accept long type parameter so change to int 

            int chunk;
            while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0)
            {
                read += chunk;

                // If we've reached the end of our buffer, check to see if there's
                // any more information.
                if (read == buffer.Length)
                {
                    int nextByte = stream.ReadByte();

                    // End of stream? If so, we're done
                    if (nextByte == -1)
                    {
                        return buffer;
                    }

                    // Nope. Resize the buffer, put in the byte we've just
                    // read, and continue
                    byte[] newBuffer = new byte[buffer.Length * 2];
                    Array.Copy(buffer, newBuffer, buffer.Length);
                    newBuffer[read] = (byte)nextByte;
                    buffer = newBuffer;
                    read++;
                }
            }

            // Buffer is now to big. Shrink it.
            byte[] ret = new byte[read];
            Array.Copy(buffer, ret, read);
            return ret;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        /// <see cref="https://stackoverflow.com/questions/221925/creating-a-byte-array-from-a-stream?rq=1"/>
        public static byte[] ReadFullyByCopyTo(Stream stream)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                // CopyTo will only copy from the current position, if you have a Seekable stream and you 
                // want to copy from the beginning then you can move to the beginning using
                // your code or input.Seek(0, SeekOrigin.Begin)
                stream.CopyTo(ms);
                return ms.ToArray();
            }
        }

    }
}
